use prost::Message;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tracing::info;

use crate::error::War3Error;
use crate::War3Message;

/// 发送protobuf消息
pub async fn send_protobuf_message<T>(
    writer: &mut (impl AsyncWriteExt + Unpin),
    message: &T,
) -> Result<(), War3Error>
where
    T: Message,
{
    let data = message.encode_to_vec();
    
    // 发送消息长度 (4字节大端序)
    let length = data.len() as u32;
    writer.write_all(&length.to_be_bytes()).await?;
    
    // 发送消息内容
    writer.write_all(&data).await?;
    writer.flush().await?;
    
    info!("发送protobuf消息: {} 字节", length);
    Ok(())
}

/// 接收protobuf消息
pub async fn receive_protobuf_message<T>(
    reader: &mut (impl AsyncReadExt + Unpin),
) -> Result<T, War3Error>
where
    T: Message + Default,
{
    // 读取消息长度 (4字节大端序)
    let mut length_bytes = [0u8; 4];
    reader.read_exact(&mut length_bytes).await?;
    let length = u32::from_be_bytes(length_bytes);
    
    if length > 1024 * 1024 {
        // 限制最大消息大小为1MB
        return Err(War3Error::InvalidMessage(format!(
            "消息太大: {} 字节", length
        )));
    }
    
    // 读取消息内容
    let mut data = vec![0u8; length as usize];
    reader.read_exact(&mut data).await?;
    
    info!("接收protobuf消息: {} 字节", length);
    
    // 解码消息
    let message = T::decode(&*data)
        .map_err(|e| War3Error::InvalidMessage(format!("解码失败: {}", e)))?;
    
    Ok(message)
}

/// 专门用于接收War3Message的函数
pub async fn receive_war3_message(
    reader: &mut (impl AsyncReadExt + Unpin),
) -> Result<War3Message, War3Error> {
    receive_protobuf_message(reader).await
}

/// 双向数据传输
pub async fn transfer_data(
    stream1: impl AsyncReadExt + AsyncWriteExt + Unpin,
    stream2: impl AsyncReadExt + AsyncWriteExt + Unpin,
) -> Result<(), Box<dyn std::error::Error>> {
    let (mut r1, mut w1) = tokio::io::split(stream1);
    let (mut r2, mut w2) = tokio::io::split(stream2);

    let client_to_server = tokio::io::copy(&mut r1, &mut w2);
    let server_to_client = tokio::io::copy(&mut r2, &mut w1);

    tokio::select! {
        res = client_to_server => {
            info!("客户端到服务器数据传输结束: {:?}", res);
            res?;
        }
        res = server_to_client => {
            info!("服务器到客户端数据传输结束: {:?}", res);
            res?;
        }
    }

    Ok(())
}